/**
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import type common from '@ohos.app.ability.common';
import BaseModel from '../../../../../../../common/utils/src/main/ets/default/model/BaseModel';
import LogUtil from '../../../../../../../common/utils/src/main/ets/default/baseUtil/LogUtil';
import relationalStore from '@ohos.data.relationalStore'
import account_osAccount from '@ohos.account.osAccount';
import huksModel from './HuksModel';
import emitter from '@ohos.events.emitter';
import VpnConfig from './VpnConfig';
import { EventId } from './VpnModel';
import StateModel from './StateModel';

const MODULE_TAG: string = 'setting_vpn:VPNRdbModel:';

const VPN_TABLE_NAME = 'VPN_PROFILES';
const TAB_VPN = {
  STORE_CONFIG: {
    name: "vpn.db",
    securityLevel: relationalStore.SecurityLevel.S1
  },
  CREATE_SQL: `CREATE TABLE IF NOT EXISTS ${VPN_TABLE_NAME} (ID INTEGER PRIMARY KEY AUTOINCREMENT,ALIAS VARCHAR,OWNER INTEGER,PROFILE BLOB,UPDATETIME TimeStamp NOT NULL DEFAULT (DATETIME('now','localtime')));`,
  COLUM: {
    ID: 'ID',
    ALIAS: 'ALIAS',
    OWNER: 'OWNER',
    PROFILE: 'PROFILE',
    UPDATETIME:'UPDATETIME'
  }
}

/**
 * app management service class
 */
class RdbModel extends BaseModel {
  private store: relationalStore.RdbStore;
  private owner: number;
  context: common.BaseContext;

  setContext(context: common.BaseContext) {
    this.context = context;
  }

  /**
   * init data
   */
  public async init(): Promise<void> {
    if (this.store) {
      LogUtil.info(MODULE_TAG + 'RdbStore had already init');
      return;
    }
    LogUtil.info(MODULE_TAG + 'init RdbStore start');
    await this.getCurrentOsAccount();
    try {
      this.store = await relationalStore.getRdbStore(this.context, TAB_VPN.STORE_CONFIG);
      await this.upgrade();
      LogUtil.info(MODULE_TAG + 'init RdbStore end');
    } catch (error) {
      LogUtil.error(MODULE_TAG + 'init RdbStore error ' + JSON.stringify(error));
    }
  }

  private async upgrade(): Promise<void> {
    LogUtil.info(MODULE_TAG + `RdbStore version ${this.store.version}`);
    switch (this.store.version) {
      case 0:
        await this.store.executeSql(TAB_VPN.CREATE_SQL).catch((error) => {
          if (error) {
            LogUtil.error(MODULE_TAG + 'RdbStore upgrade error:' + JSON.stringify(error));
          } else {
            this.store.version = 1;
            LogUtil.error(MODULE_TAG + 'RdbStore upgrade success: version = 1');
          }
        })
        break;
    }
  }

  /**
   * query
   */
  async queryAll(): Promise<void> {
    await this.init();
    LogUtil.info(MODULE_TAG + "queryAll start");
    let predicates = new relationalStore.RdbPredicates(VPN_TABLE_NAME);
    predicates.equalTo(TAB_VPN.COLUM.OWNER, this.owner);
    predicates.orderByAsc(TAB_VPN.COLUM.ALIAS).orderByAsc(TAB_VPN.COLUM.UPDATETIME);
    let results: VpnConfig[] = [];
    let resultSet: relationalStore.ResultSet = await this.store.query(predicates);

    let currentConnectVpn: VpnConfig | undefined = undefined;
    let currentConnectVpnId = AppStorage.get<StateModel>('connectState')?.vpnId;
    while (resultSet.goToNextRow()) {

      let id: number = resultSet.getLong(resultSet.getColumnIndex(TAB_VPN.COLUM.ID));
      let profile: Uint8Array = resultSet.getBlob(resultSet.getColumnIndex(TAB_VPN.COLUM.PROFILE));
      let vpn = await huksModel.decryptData(profile);
      vpn.alias = decodeURIComponent(vpn.alias);
      vpn.id = id;
      if(currentConnectVpnId == id) {
        currentConnectVpn = vpn;
      } else {
        results.push(vpn);
      }
    }
    if(currentConnectVpn) {
      results.unshift(currentConnectVpn); //将当前连接的vpn添加到第一个
    }
    resultSet?.close();
    emitter.emit(EventId.VPN_LIST, { data: results });
  }

  /**
   * insert
   * @param valueBucket
   */
  insert(vpn: VpnConfig, callback): void {
    LogUtil.info(MODULE_TAG + `insert vpn start}`);

    huksModel.encryptData(vpn, (profile: Uint8Array) => {
      let valueBucket = {
        ALIAS: encodeURIComponent(vpn.alias),
        OWNER: this.owner,
        PROFILE: profile,
      };

      this.store.insert(VPN_TABLE_NAME, valueBucket).then(rowid => {
        LogUtil.info(MODULE_TAG + `insert success`);
        callback();
      }, error => {
        callback(error);
        LogUtil.error(MODULE_TAG + `insert error:${error}`);
      })
    })
  }

  /**
   * update
   * @param id
   * @param valueBucket
   */
  update(vpn: VpnConfig, callback): void {
    let dbVpn:VpnConfig = Object.assign({},vpn);
    if(!vpn.saveLogin) {
      dbVpn.username = undefined;
      dbVpn.password = undefined;
    }

    huksModel.encryptData(dbVpn, (profile: Uint8Array) => {
      let valueBucket = {
        ALIAS:encodeURIComponent(vpn.alias),
        PROFILE: profile
      };
      let predicates = new relationalStore.RdbPredicates(VPN_TABLE_NAME);
      predicates.equalTo(TAB_VPN.COLUM.ID, vpn.id)
      predicates.equalTo(TAB_VPN.COLUM.OWNER, this.owner);

      this.store.update(valueBucket, predicates).then((row) => {
        LogUtil.info(MODULE_TAG + `update success`);
        callback();
      }, (error) => {
        LogUtil.error(MODULE_TAG + `update error:${error}`);
      })
    })
  }

  /**
   * delete vpn
   * @param id
   */
  delete(id: number, callback): void {
    let predicates = new relationalStore.RdbPredicates(VPN_TABLE_NAME);
    predicates.equalTo(TAB_VPN.COLUM.ID, id)
    predicates.equalTo(TAB_VPN.COLUM.OWNER, this.owner);
    this.store.delete(predicates).then((row) => {
      LogUtil.info(MODULE_TAG + `delete success`);
      callback();
    }, (error) => {
      LogUtil.error(MODULE_TAG + `delete error:${error}`)
    })
  }

  /**
   * get accountId
   * @returns
   */
  async getCurrentOsAccount(): Promise<void> {
    if (this.owner) return;
    try {
      let accountManager: account_osAccount.AccountManager = account_osAccount.getAccountManager();
      let accountInfo: account_osAccount.OsAccountInfo = await accountManager.getCurrentOsAccount()
      this.owner = accountInfo.serialNumber;
    } catch (error) {
      LogUtil.error(MODULE_TAG + `getCurrentOsAccount error:${error}`);
    }
  }
}

let rdbModel = new RdbModel();

export default rdbModel;

